package com.gitee.kenewstar.migration.function;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gitee.kenewstar.migration.constants.Const;
import com.gitee.kenewstar.migration.constants.FunctionCode;
import com.gitee.kenewstar.migration.core.AbstractSyncFunction;
import com.gitee.kenewstar.migration.core.ContextParam;
import com.gitee.kenewstar.migration.entity.CommonResult;
import com.gitee.kenewstar.migration.entity.Lov;
import com.gitee.kenewstar.migration.entity.LovViewHeader;
import com.gitee.kenewstar.migration.entity.LovViewHeaderTl;
import com.gitee.kenewstar.migration.entity.LovViewLine;
import com.gitee.kenewstar.migration.entity.LovViewLineTl;
import com.gitee.kenewstar.migration.service.LovService;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author kenewstar
 */
@Slf4j
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class LovViewFunction extends AbstractSyncFunction<LovViewHeader> {

    private final LovService lovService;

    @Override
    protected Class<LovViewHeader> parameterType() {
        return LovViewHeader.class;
    }
    @Override
    public FunctionCode functionCode() {
        return FunctionCode.LOV_VIEW;
    }

    @Override
    public List<CommonResult> execute(ContextParam contextParam, List<LovViewHeader> list) {
        // 查询视图
        final List<LovViewHeader> headerList = this.lovService.devSelectLovHeaderList(list);
        if (CollUtil.isEmpty(headerList)) {
            return Collections.emptyList();
        }

        final List<Lov> devLovList = this.lovService.devSelectLov(headerList.stream().map(LovViewHeader::getLovId).collect(Collectors.toList()));
        final List<Lov> uatLovList = this.lovService.uatSelectLov(devLovList.stream().map(Lov::getLovCode).collect(Collectors.toList()));
        Map<Long, Long> devUatLovMap = new HashMap<>(uatLovList.size());

        // dev lovId -> uat lovId
        Map<String, Long> uatLovIdMap = new HashMap<>(uatLovList.size());
        uatLovList.forEach(x -> uatLovIdMap.put(x.getLovCode() + "," + x.getTenantId(), x.getLovId()));
        devLovList.forEach(x -> devUatLovMap.put(x.getLovId(), uatLovIdMap.get(x.getLovCode() + "," + x.getTenantId())));

        QueryWrapper<LovViewHeaderTl> headerTlQueryWrapper = new QueryWrapper<>();
        headerTlQueryWrapper.in("view_header_id", headerList.stream().map(LovViewHeader::getViewHeaderId).collect(Collectors.toList()));
        final List<LovViewHeaderTl> lovViewHeaderTls = this.lovService.devSelectLovHeaderTl(headerTlQueryWrapper);
        final Map<Long, List<LovViewHeaderTl>> headerTlsMap = lovViewHeaderTls.stream().collect(Collectors.groupingBy(LovViewHeaderTl::getViewHeaderId));

        QueryWrapper<LovViewLine> lineQueryWrapper = new QueryWrapper<>();
        lineQueryWrapper.in("view_header_id", headerList.stream().map(LovViewHeader::getViewHeaderId).collect(Collectors.toList()));
        final List<LovViewLine> lineList = this.lovService.devSelectLovLine(lineQueryWrapper);
        final Map<Long, List<LovViewLine>> lineMap = lineList.stream().collect(Collectors.groupingBy(LovViewLine::getViewHeaderId));

        final List<Long> viewLineIds = lineList.stream().map(LovViewLine::getViewLineId).collect(Collectors.toList());
        final Map<Long, List<LovViewLineTl>> lovViewLineTlsMap;
        if (CollUtil.isNotEmpty(viewLineIds)) {
            QueryWrapper<LovViewLineTl> lineTlQueryWrapper = new QueryWrapper<>();
            lineTlQueryWrapper.in("view_line_id", viewLineIds);
            final List<LovViewLineTl> lovViewLineTls = this.lovService.devSelectLovLineTl(lineTlQueryWrapper);
            lovViewLineTlsMap = lovViewLineTls.stream().collect(Collectors.groupingBy(LovViewLineTl::getViewLineId));
        } else {
            lovViewLineTlsMap = new HashMap<>(0);
        }

        contextParam.lovViewConext = Context.builder().build();
        contextParam.lovViewConext.devUatLovMap = devUatLovMap;
        contextParam.lovViewConext.headerTlsMap = headerTlsMap;
        contextParam.lovViewConext.lineMap = lineMap;
        contextParam.lovViewConext.lovViewLineTlsMap = lovViewLineTlsMap;

        List<CommonResult> results = new ArrayList<>();
        headerList.forEach(x -> {
            try {
                contextParam.lovViewConext.lovViewHeader = x;
                this.self().singleExecute(contextParam);
                results.add(CommonResult.create(true).setLovViewCode(x.getViewCode()));
            } catch (Exception e) {
                results.add(CommonResult.create(false).setLovViewCode(x.getViewCode()).setErrorMsg(e.getMessage()));
                e.printStackTrace();
            }
        });
        return results;
    }



    @Override
    @DS(Const.UAT)
    @Transactional(rollbackFor = Exception.class)
    public void singleExecute(ContextParam contextParam) {
        LovViewHeader header = contextParam.lovViewConext.lovViewHeader;
        Map<Long, Long> devUatLovMap = contextParam.lovViewConext.devUatLovMap;
        Map<Long, List<LovViewHeaderTl>> headerTlsMap = contextParam.lovViewConext.headerTlsMap;
        Map<Long, List<LovViewLine>> lineMap = contextParam.lovViewConext.lineMap;
        Map<Long, List<LovViewLineTl>> lovViewLineTlsMap = contextParam.lovViewConext.lovViewLineTlsMap;

        Long devHeaderId = header.getViewHeaderId();

        header.setViewHeaderId(null);
        Long uatLovId = devUatLovMap.get(header.getLovId());
        Assert.notNull(uatLovId, "目标环境值集不存在");
        header.setLovId(uatLovId);
        this.lovService.uatInsertLovHeader(ListUtil.toList(header));

        // 插入多语言数据
        final List<LovViewHeaderTl> headerTls = headerTlsMap.get(devHeaderId);
        headerTls.forEach(v -> v.setViewHeaderId(header.getViewHeaderId()));
        this.lovService.uatInsertLovHeaderTl(headerTls);

        // 插入视图行数据
        final List<LovViewLine> viewLines = lineMap.get(devHeaderId);
        if (CollUtil.isEmpty(viewLines)) {
            return;
        }
        viewLines.forEach(v -> v.setDevViewLineId(v.getViewLineId()));
        viewLines.forEach(v -> v.setLovId(header.getLovId()));
        viewLines.forEach(v -> v.setViewLineId(null));
        viewLines.forEach(v -> v.setViewHeaderId(header.getViewHeaderId()));
        this.lovService.uatInsertLovLine(viewLines);

        List<LovViewLineTl> list = new ArrayList<>(10);
        for (LovViewLine viewLine : viewLines) {
            List<LovViewLineTl> viewLineTls = lovViewLineTlsMap.get(viewLine.getDevViewLineId());
            viewLineTls.forEach(v -> v.setViewLineId(viewLine.getViewLineId()));
            list.addAll(viewLineTls);
        }
        this.lovService.uatInsertLovLineTl(list);
    }

    @Builder
    @SuppressWarnings("all")
    public static class Context {
        public LovViewHeader lovViewHeader;
        public Map<Long, Long> devUatLovMap;
        public Map<Long, List<LovViewHeaderTl>> headerTlsMap;
        public Map<Long, List<LovViewLine>> lineMap;
        public Map<Long, List<LovViewLineTl>> lovViewLineTlsMap;

    }

}
